#ifdef __cplusplus
extern "C"
{
#endif

#include "esp_log.h"
#include "esp_wifi_remote.h"
#include "nvs_flash.h"
#include "esp_sntp.h"
#include "time.h"
#include "sys/time.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "string.h"

#ifdef __cplusplus
}
#endif

// std
#include <algorithm>
#include <string>
#include <unordered_set>
#include <vector>


#define WIFI_SSID "Sila_2.4G"
#define WIFI_PASS "87845766"

// 网络时间服务器配置
#define SNTP_SERVER1 "pool.ntp.org"
#define SNTP_SERVER2 "time.nist.gov"
#define SNTP_SERVER3 "cn.pool.ntp.org"  // 中国时间服务器

static bool time_sync_complete = false;

// 时间同步回调函数
void time_sync_notification_cb(struct timeval *tv)
{
    ESP_LOGI("Time Sync", "时间同步完成！");
    time_sync_complete = true;
    
    // 获取当前时间
    time_t now = 0;
    struct tm timeinfo = {};  // 使用{}初始化避免警告
    time(&now);
    
    // 设置时区为中国标准时间 (UTC+8)
    setenv("TZ", "CST-8", 1);
    tzset();
    
    localtime_r(&now, &timeinfo);
    
    char strftime_buf[64];
    strftime(strftime_buf, sizeof(strftime_buf), "%Y-%m-%d %H:%M:%S", &timeinfo);
    ESP_LOGI("Time Sync", "当前北京时间: %s", strftime_buf);
    
    // 显示星期几
    const char* weekdays[] = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
    ESP_LOGI("Time Sync", "今天是: %s", weekdays[timeinfo.tm_wday]);
}

// 初始化SNTP时间同步
void initialize_sntp(void)
{
    ESP_LOGI("SNTP", "初始化网络时间同步...");
    
    // 设置时间同步回调
    sntp_set_time_sync_notification_cb(time_sync_notification_cb);
    
    // 设置操作模式
    esp_sntp_setoperatingmode(SNTP_OPMODE_POLL);
    
    // 设置时间服务器
    esp_sntp_setservername(0, SNTP_SERVER1);
    esp_sntp_setservername(1, SNTP_SERVER2);
    esp_sntp_setservername(2, SNTP_SERVER3);
    
    // 启动SNTP
    esp_sntp_init();
    
    ESP_LOGI("SNTP", "SNTP 服务器配置:");
    ESP_LOGI("SNTP", "  服务器1: %s", SNTP_SERVER1);
    ESP_LOGI("SNTP", "  服务器2: %s", SNTP_SERVER2);
    ESP_LOGI("SNTP", "  服务器3: %s", SNTP_SERVER3);
}

// 显示网络时间
void display_network_time(void)
{
    if (!time_sync_complete) {
        ESP_LOGW("Time", "时间尚未同步，等待网络时间...");
        return;
    }
    
    time_t now = 0;
    struct tm timeinfo = {};  // 使用{}初始化避免警告
    time(&now);
    localtime_r(&now, &timeinfo);
    
    char strftime_buf[64];
    strftime(strftime_buf, sizeof(strftime_buf), "%Y年%m月%d日 %H:%M:%S", &timeinfo);
    
    const char* weekdays[] = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
    
    ESP_LOGI("Network Time", "===============================================");
    ESP_LOGI("Network Time", "当前北京时间: %s %s", strftime_buf, weekdays[timeinfo.tm_wday]);
    ESP_LOGI("Network Time", "Unix时间戳: %lld", (long long)now);  // 修复格式字符串
    ESP_LOGI("Network Time", "===============================================");
}

static void wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
{
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START)
    {
        ESP_LOGI("Wi-Fi Event", "WiFi 站点模式启动，开始连接...");
        esp_wifi_remote_connect();
    }
    else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_CONNECTED)
    {
        wifi_event_sta_connected_t* event = (wifi_event_sta_connected_t*)event_data;
        ESP_LOGI("Wi-Fi Event", "WiFi 连接成功！SSID: %s, 信道: %d", event->ssid, event->channel);
    }
    else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP)
    {
        ip_event_got_ip_t* event = (ip_event_got_ip_t*)event_data;
        ESP_LOGI("Wi-Fi Event", "==================================================");
        ESP_LOGI("Wi-Fi Event", "🎉 网络连接成功！");
        ESP_LOGI("Wi-Fi Event", "📍 IP地址: " IPSTR, IP2STR(&event->ip_info.ip));
        ESP_LOGI("Wi-Fi Event", "📍 网关地址: " IPSTR, IP2STR(&event->ip_info.gw));
        ESP_LOGI("Wi-Fi Event", "📍 子网掩码: " IPSTR, IP2STR(&event->ip_info.netmask));
        ESP_LOGI("Wi-Fi Event", "==================================================");

        // 启动网络时间同步
        initialize_sntp();

        // 注意：不在这里立即扫描WiFi，而是让专门的扫描任务来处理
        // 避免在刚连接网络时进行扫描，可能会影响网络稳定性
    }
    else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED)
    {
        wifi_event_sta_disconnected_t* event = (wifi_event_sta_disconnected_t*)event_data;
        ESP_LOGI("Wi-Fi Event", "WiFi 断开连接，原因: %d, RSSI: %d", event->reason, event->rssi);
        
        // 根据断开原因给出详细信息
        switch(event->reason) {
            case WIFI_REASON_AUTH_EXPIRE:
                ESP_LOGW("Wi-Fi Event", "认证过期");
                break;
            case WIFI_REASON_AUTH_LEAVE:
                ESP_LOGW("Wi-Fi Event", "认证离开");
                break;
            case WIFI_REASON_ASSOC_EXPIRE:
                ESP_LOGW("Wi-Fi Event", "关联过期");
                break;
            case WIFI_REASON_ASSOC_TOOMANY:
                ESP_LOGW("Wi-Fi Event", "关联数量过多");
                break;
            case WIFI_REASON_NOT_AUTHED:
                ESP_LOGW("Wi-Fi Event", "未认证");
                break;
            case WIFI_REASON_NOT_ASSOCED:
                ESP_LOGW("Wi-Fi Event", "未关联");
                break;
            case WIFI_REASON_ASSOC_LEAVE:
                ESP_LOGW("Wi-Fi Event", "关联离开");
                break;
            case WIFI_REASON_ASSOC_NOT_AUTHED:
                ESP_LOGW("Wi-Fi Event", "关联未认证");
                break;
            case WIFI_REASON_DISASSOC_PWRCAP_BAD:
                ESP_LOGW("Wi-Fi Event", "功率能力不匹配");
                break;
            case WIFI_REASON_DISASSOC_SUPCHAN_BAD:
                ESP_LOGW("Wi-Fi Event", "支持的信道不匹配");
                break;
            case WIFI_REASON_IE_INVALID:
                ESP_LOGW("Wi-Fi Event", "无效的信息元素");
                break;
            case WIFI_REASON_MIC_FAILURE:
                ESP_LOGW("Wi-Fi Event", "MIC失败");
                break;
            case WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT:
                ESP_LOGW("Wi-Fi Event", "四次握手超时");
                break;
            case WIFI_REASON_GROUP_KEY_UPDATE_TIMEOUT:
                ESP_LOGW("Wi-Fi Event", "组密钥更新超时");
                break;
            case WIFI_REASON_IE_IN_4WAY_DIFFERS:
                ESP_LOGW("Wi-Fi Event", "四次握手中IE不同");
                break;
            case WIFI_REASON_GROUP_CIPHER_INVALID:
                ESP_LOGW("Wi-Fi Event", "无效的组密码");
                break;
            case WIFI_REASON_PAIRWISE_CIPHER_INVALID:
                ESP_LOGW("Wi-Fi Event", "无效的成对密码");
                break;
            case WIFI_REASON_AKMP_INVALID:
                ESP_LOGW("Wi-Fi Event", "无效的AKMP");
                break;
            case WIFI_REASON_UNSUPP_RSN_IE_VERSION:
                ESP_LOGW("Wi-Fi Event", "不支持的RSN IE版本");
                break;
            case WIFI_REASON_INVALID_RSN_IE_CAP:
                ESP_LOGW("Wi-Fi Event", "无效的RSN IE能力");
                break;
            case WIFI_REASON_802_1X_AUTH_FAILED:
                ESP_LOGW("Wi-Fi Event", "802.1X认证失败");
                break;
            case WIFI_REASON_CIPHER_SUITE_REJECTED:
                ESP_LOGW("Wi-Fi Event", "密码套件被拒绝");
                break;
            case WIFI_REASON_BEACON_TIMEOUT:
                ESP_LOGW("Wi-Fi Event", "信标超时");
                break;
            case WIFI_REASON_NO_AP_FOUND:
                ESP_LOGW("Wi-Fi Event", "未找到AP");
                break;
            case WIFI_REASON_AUTH_FAIL:
                ESP_LOGW("Wi-Fi Event", "认证失败 - 请检查WiFi密码");
                break;
            case WIFI_REASON_ASSOC_FAIL:
                ESP_LOGW("Wi-Fi Event", "关联失败");
                break;
            case WIFI_REASON_HANDSHAKE_TIMEOUT:
                ESP_LOGW("Wi-Fi Event", "握手超时");
                break;
            case WIFI_REASON_CONNECTION_FAIL:
                ESP_LOGW("Wi-Fi Event", "连接失败");
                break;
            default:
                ESP_LOGW("Wi-Fi Event", "未知断开原因: %d", event->reason);
                break;
        }
        
        ESP_LOGI("Wi-Fi Event", "尝试重新连接...");
        esp_wifi_remote_connect();
    }
    else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_SCAN_DONE)
    {
        ESP_LOGI("Wi-Fi Event", "🔍 WiFi 扫描完成！正在获取热点列表...");
        uint16_t ap_count = 0;
        std::vector<wifi_ap_record_t> ap_info;

        // 获取扫描结果数量 - 使用remote版本
        if (esp_wifi_remote_scan_get_ap_num(&ap_count) != ESP_OK)
        {
            ESP_LOGE("Wi-Fi Event", "❌ 获取 AP 数量失败");
            return;
        }

        if (ap_count == 0) {
            ESP_LOGW("Wi-Fi Event", "⚠️ 未扫描到任何WiFi热点");
            return;
        }

        // 限制最大获取数量，避免内存不足
        uint16_t max_aps = ap_count;
        if (max_aps > 32) {
            max_aps = 32;  // 减少到32个以避免内存问题
        }
        ap_info.resize(max_aps);

        // 获取 Wi-Fi 热点信息 - 使用remote版本
        if (esp_wifi_remote_scan_get_ap_records(&max_aps, ap_info.data()) != ESP_OK)
        {
            ESP_LOGE("Wi-Fi Event", "❌ 获取 AP 记录失败");
            return;
        }

        ESP_LOGI("Wi-Fi Event", "📶 扫描到 %d 个 Wi-Fi 热点（显示前%d个）：", ap_count, max_aps);

        // **按信号强度 RSSI 降序排序**
        std::sort(ap_info.begin(), ap_info.end(),
                  [](const wifi_ap_record_t& a, const wifi_ap_record_t& b)
                  {
                      return a.rssi > b.rssi; // RSSI 越大信号越强
                  });

        // **去重 SSID**
        std::unordered_set<std::string> seen_ssids;
        std::vector<wifi_ap_record_t> unique_ap_info;

        for (const auto& info : ap_info)
        {
            std::string ssid_str(reinterpret_cast<const char*>(info.ssid)); // 转换为 std::string
            if (!ssid_str.empty() && seen_ssids.find(ssid_str) == seen_ssids.end())
            {
                seen_ssids.emplace(ssid_str);
                unique_ap_info.emplace_back(info);
            }
        }

        // **遍历并打印 Wi-Fi 热点信息**
        ESP_LOGI("Wi-Fi Event", "════════════════════════════════════════════════════════════════════════════");
        ESP_LOGI("Wi-Fi Event", "║ %-32s ║ %-6s ║ %-9s ║ %-17s ║", "SSID", "RSSI", "Channel", "MAC Address");
        ESP_LOGI("Wi-Fi Event", "════════════════════════════════════════════════════════════════════════════");

        for (size_t i = 0; i < unique_ap_info.size() && i < 15; i++) // 最多显示15个
        {
            const auto& info = unique_ap_info[i];
            const char* band = (info.primary <= 14) ? "2.4GHz" : "5GHz";
            
            // 根据信号强度显示不同的图标
            const char* signal_icon = "📶";
            if (info.rssi >= -30) signal_icon = "📶💚";      // 极强
            else if (info.rssi >= -50) signal_icon = "📶💛";  // 强
            else if (info.rssi >= -70) signal_icon = "📶🧡";  // 中等
            else if (info.rssi >= -80) signal_icon = "📶❤️";  // 弱
            else signal_icon = "📶💔";                        // 很弱
            
            ESP_LOGI("Wi-Fi Event", "║ %-32s ║ %4d ║ %3d (%s) ║ %02X:%02X:%02X:%02X:%02X:%02X ║ %s", 
                     info.ssid, info.rssi, info.primary, band, 
                     info.bssid[0], info.bssid[1], info.bssid[2], 
                     info.bssid[3], info.bssid[4], info.bssid[5], signal_icon);
        }

        ESP_LOGI("Wi-Fi Event", "════════════════════════════════════════════════════════════════════════════");
        ESP_LOGI("Wi-Fi Event", "📊 总计发现 %zu 个不重复的WiFi热点", unique_ap_info.size());
    }
    else
    {
        ESP_LOGI("Wi-Fi Event", "event %s %ld", event_base, event_id);
    }
}

void wifi_init_sta()
{
    // Initialize NVS
    esp_err_t err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND)
    {
        // NVS partition was truncated and needs to be erased
        // Retry nvs_flash_init
        ESP_ERROR_CHECK(nvs_flash_erase());
        err = nvs_flash_init();
    }
    ESP_ERROR_CHECK(err);
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());

    esp_netif_create_default_wifi_sta();

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_remote_init(&cfg));

    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, NULL));
    ESP_ERROR_CHECK(
        esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL, NULL));

    wifi_config_t wifi_config = {};  // 初始化为零
    strcpy((char*)wifi_config.sta.ssid, WIFI_SSID);
    strcpy((char*)wifi_config.sta.password, WIFI_PASS);

    ESP_ERROR_CHECK(esp_wifi_remote_set_mode(WIFI_MODE_STA));
    ESP_ERROR_CHECK(esp_wifi_remote_set_config(WIFI_IF_STA, &wifi_config));
    ESP_ERROR_CHECK(esp_wifi_remote_start());
}

/*
- **事件驱动机制**  
  通过注册事件处理器，我们能够在 Wi-Fi 启动、连接、断开和扫描完成等状态时，自动调用相应函数，实现自动连接与扫描功能。这种事件驱动机制极大地简化了状态管理，提高了系统稳定性。

- **Wi-Fi 扫描与排序**  
  在获得 IP 后，系统会主动启动扫描功能，并对扫描到的热点列表按 RSSI 信号强度进行降序排序，再通过哈希去重避免重复 SSID 的干扰，从而清晰展示热点信息。

- **自动重连功能**  
  当 Wi-Fi 连接断开时，系统会自动重新尝试连接目标网络，确保网络连接的持续性和可靠性。
*/

// 时间显示任务
void time_display_task(void* pvParameters)
{
    while (1) {
        // 每30秒显示一次时间
        vTaskDelay(pdMS_TO_TICKS(30000));
        display_network_time();
    }
}

// WiFi扫描任务
void wifi_scan_task(void* pvParameters)
{
    // 等待WiFi连接完成
    vTaskDelay(pdMS_TO_TICKS(10000));
    
    while (1) {
        ESP_LOGI("WiFi Scan", "🔄 开始定期WiFi扫描...");
        
        wifi_scan_config_t scan_config = {};  // 初始化为零
        scan_config.ssid = NULL;         // NULL 表示扫描所有 SSID
        scan_config.bssid = NULL;        // NULL 表示扫描所有 AP
        scan_config.channel = 0;         // 0 表示扫描所有信道
        scan_config.show_hidden = true;  // 显示隐藏SSID
        scan_config.scan_type = WIFI_SCAN_TYPE_ACTIVE;

        esp_err_t err = esp_wifi_remote_scan_start(&scan_config, false);
        if (err != ESP_OK) {
            ESP_LOGE("WiFi Scan", "❌ 启动WiFi扫描失败: %s", esp_err_to_name(err));
        }
        
        // 每2分钟扫描一次
        vTaskDelay(pdMS_TO_TICKS(120000));
    }
}

// WiFi api 参考 https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html
extern "C" void app_main(void) { 
    wifi_init_sta(); 
    
    // 创建时间显示任务
    xTaskCreate(time_display_task, "time_display", 4096, NULL, 5, NULL);
    
    // 创建WiFi扫描任务
    xTaskCreate(wifi_scan_task, "wifi_scan", 8192, NULL, 4, NULL);
}
